package evs.location;

import java.io.IOException;
import java.util.List;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.hibernate.HibernateException;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.search.FullTextQuery;
import org.hibernate.search.FullTextSession;
import org.hibernate.search.Search;
import org.hibernate.search.query.dsl.QueryBuilder;

public class FulltextSearchRequestHandler extends AbstractRequestHandler
{
    public FulltextSearchRequestHandler( HttpServletRequest request, SessionFactory sessionFactory,
                    List<Class<?>> interceptorClasses, EntityMap entityMap ) throws EvsException
    {
        super( request, sessionFactory, interceptorClasses, entityMap );
        
    }

    @Override
    protected Class<?> _getExpectedEntityClass()
    {
        String requestPath = extractPath( _request );
        
        int beginOfEntityName = requestPath.indexOf( '/' ) + 1;
        int endOfEntityName = requestPath.indexOf( '/', beginOfEntityName );
        
        String entityName = endOfEntityName < 0 ?
            requestPath.substring( beginOfEntityName ) :
            requestPath.substring( beginOfEntityName, endOfEntityName );
        
        return _entityMap.getEntityForPath( entityName );
    }
    
    @Override
    protected boolean allowUnknownMediaType() { return false; }

    @Override
    protected void _execute( HttpServletResponse response ) throws EvsException
    {
        Session session = null;
        Transaction tx = null;
        
        try
        {
            session = _sessionFactory.openSession();
            FullTextSession fs = Search.getFullTextSession( session );
            
            tx = session.beginTransaction();
            
            Class<?> entityClass = _getExpectedEntityClass();
            
            QueryBuilder qb = fs.getSearchFactory()
                                .buildQueryBuilder()
                                .forEntity( entityClass )
                                .get();
            
            FullTextQuery query = fs.createFullTextQuery( 
                            qb.keyword()
                            .onFields( _entityMap.getFulltextSearchFields( entityClass ) )
                            .matching( _getSearchTerm() )
                            .createQuery(), 
                            entityClass );
            
            EntityDom rootDom = new EntityDom();
            rootDom.name = "results";
            rootDom.isCollection = true;
            
            for ( Object result : query.list() )
            {
                EntitySerializer serializer = new EntitySerializer( _entityMap );
                EntityDom dom = serializer.serialize( result );
                
                rootDom.addChild( dom );
            }
            
            if ( _mediaType == MediaType.XML )
            {
                response.getWriter().write( rootDom.toXML() );
            }
            else
            {
                response.getWriter().write( rootDom.toJson() );
            }
            
            tx.commit();
            tx = null;
        }
        catch ( HibernateException e )
        {
            e.printStackTrace();
            throw new EvsException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            "Hibernate error: " + e.getMessage() );
        }
        catch ( IOException e )
        {
            throw new EvsException( HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
                            e.getMessage() );
        }
        finally
        {
            if ( tx!= null )
            {
                tx.rollback();
                tx = null;
            }
            
            if ( session != null )
            {
                session.close();
            }
        }

    }

    private String _getSearchTerm() throws EvsException
    {
        String value = _request.getParameter( "term" );

        if ( value == null )
            throw new EvsException( HttpServletResponse.SC_BAD_REQUEST,
                            "No search term given!" );

        return value;
    }

}
